package com.soap.desensitize.strategy.rreversible.symmetry;


import com.soap.desensitize.encry.rreversible.symmetry.AbstractSymmetryEncry;
import com.soap.desensitize.exception.strategy.DecodeException;
import sun.misc.BASE64Decoder;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 * @author  QGP
 * @version 1.0
 * @desc    AES加解密
 * @date    2022-04-23
 * @since   JDK 1.8
 */
public class AesStrategy extends AbstractSymmetryEncry<String> {

    /**
     * 需要16位 密码
     */
    private String password="1234567812345678";
    /**
     * 密钥算法
     */
    private static final String ALGORITHM = "AES";

    /**
     * 静态常量
     */
    private static final String AES = "AES";

    /**
     * 默认编码
     */
    private static final String CHARSET = "utf-8";

    private static AesStrategy instance = null;
    /**
     * @desc 获得实例
     * @return
     */
    public static synchronized AesStrategy getInstance(){
        if(instance == null){
            instance = new AesStrategy();
        }
        return instance;
    }


    /**
     * @desc 默认使用子类加密密码
     */
    private AesStrategy(){
        super.password=this.password;
    }


    /**
     * @desc  将字符串【AES加密】为base 64 code
     * @param password
     * @param data
     * @return
     */
    @Override
    public String encode(String password, String data) {
        try {
            // 创建密码器
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            kgen.init(128);
            // 初始化为加密模式的密码器
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(password.getBytes(), AesStrategy.AES));

            byte[] bytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
            // 使用base64解码
            return new String(Base64.getEncoder().encode(bytes));
        } catch (Exception e) {
            System.out.println(e.getMessage() + e);
        }
        return null;
    }

    /**
     * 将base 64 code 【AES解密】为字符串
     * @param password 密码
     * @param data  字符数据
     * @return 解密后的数据
     * @throws DecodeException 解密异常
     */
    @Override
    public String decode(String password, String data) throws DecodeException {
        if (data.isEmpty()) {
            throw new DecodeException("加密数据不能为空 ");
        }
        byte[] decryptBytes = new byte[0];
        try {
            // 将字符串转为byte，返回解码后的byte[]
            byte[] encryptBytes = new BASE64Decoder().decodeBuffer(data);


            // 1.获取加密算法工具类
            KeyGenerator kgen = KeyGenerator.getInstance(AesStrategy.AES);
            kgen.init(128);
            // 初始化为解密模式的密码器
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(password.getBytes(), AesStrategy.AES));
            decryptBytes = cipher.doFinal(encryptBytes);
        } catch (IOException e) {
            throw new DecodeException("io异常 "+e.getMessage());
        } catch (NoSuchPaddingException e) {
            throw new DecodeException("无此类删除异常 "+e.getMessage());
        } catch (IllegalBlockSizeException e) {
            throw new DecodeException("非法块大小异常 "+e.getMessage());
        } catch (BadPaddingException e) {
            throw new DecodeException("填充异常 "+e.getMessage());
        } catch (NoSuchAlgorithmException e) {
            throw new DecodeException("未找到该算法 "+e.getMessage());
        } catch (InvalidKeyException e) {
            throw new DecodeException(e.getMessage());
        }
        return new String(decryptBytes);
    }


    /**
     * @desc 使用默认加密密码，加密
     */
    @Override
    public String encode(String data){
        if (getPassword()!=null){
            return encode(getPassword(), data);
        }
        return encode(password, data);
    }

    /**
     * @desc 使用默认加密密码，解密
     */
    @Override
    public String decode(String data) throws DecodeException {
        if (getPassword() != null) {
            return decode(getPassword(), data);
        }
        return decode(password, data);
    }
}

